<meta charset='utf8' />
<canvas id='canvas' width='256px' height='256px'></canvas>
<script type="text/javascript">
function add(v1, v2){
	return [v1[0]+v2[0],v1[1]+v2[1],v1[2]+v2[2]];
}
function subtract(v1, v2){
	return [v1[0]-v2[0],v1[1]-v2[1],v1[2]-v2[2]];
}
function multiply(v, f){
	return [v[0]*f,v[1]*f,v[2]*f];
}
function divide(v, f){
	return multiply(v, 1 / f);
}
function normalize(v){
	return multiply(v, 1 / Math.sqrt(dot(v, v)));
}
function negate(v){
	return [-v[0],-v[1],-v[2]];
}
function dot(v1, v2){
	return v1[0]*v2[0]+v1[1]*v2[1]+v1[2]*v2[2];
}
function sequare(v){
	return dot(v, v);
}
function cross(v1, v2){
	return [v1[2] * v2[1] - v1[1] * v2[2], v1[0] * v2[2] - v1[2] * v2[0], v1[1] * v2[0] - v1[0] * v2[1]];
}

//ray
function Ray3(origin, direction){
	return [origin, direction];
}
function getPoint(ray, t){
	return add(ray[0], multiply(ray[1], t))
}
//sphere
function Sphere(center, radius){
	return [center, radius, radius * radius];
}
function intersect(sphere, ray){
	v = subtract(ray[0], sphere[0]);
	DdotV = dot(ray[1], v);
	a0 = sequare(v) - sphere[2];
	discr = DdotV * DdotV - a0;
	if(discr < 0){
		return null;
	}
	disSqrt = Math.sqrt(discr);
	d1 = -DdotV - disSqrt;
	d2 = -DdotV + disSqrt;

	result = [0, 0, 0, 0, 0];
	ddir = 0;
	if(d1 > 0.0001){
		result[0] = d1;
		result[1] = 1;
	}else if(d1 > 0.0001){
		result[0] = d2;
		result[1] = -1;
	}else{
		return null;
	}
	result[2] = sphere;
	result[3] = getPoint(ray, result[0]);
	result[4] = normalize(subtract(result[3], sphere[0]));
	if(result[1] == -1){
		result[4] = negate(result[4]);
	}
	return result;
}

var Camera = function(eye, front, up, fov){
	this.eye = eye;
	this.front = front;
	this.up = up;
	this.fov = fov;
}

Camera.prototype.initialize = function(){
	this.right = cross(this.up, this.front);
	this.up = cross(this.right, this.front);
	this.fovScale = Math.tan(this.fov / 2 * Math.PI / 180);
}
Camera.prototype.generateRay = function(x, y){
	r = multiply(this.right, x * this.fovScale);
	u = multiply(this.up, y * this.fovScale);
	return Ray3(this.eye, normalize(add(add(this.front, r), u)));
}


function renderDepth(scene, camera) {
	var w = canvas.width;
	var h = canvas.height;
	var ctx = canvas.getContext('2d');
	ctx.fillRect(0, 0, w, h);
	var imgData = ctx.getImageData(0, 0, w, h);
	var pixels = imgData.data;

	camera.initialize();

	var i = 0;
	var sx, sy, ray, result, depth;
	for(var y = 0; y < h; y++){
		sy = 2 * y / h - 1;	
		for(var x = 0; x < w; x++){
			sx = 2 * x / w - 1;
			ray = camera.generateRay(sx, sy);
			result = intersect(scene, ray);
			if(result){
				depth = 255 - Math.min((result[0] / 20) * 255, 255);
				pixels[i] = depth;
				pixels[i + 1] = depth;
				pixels[i + 2] = depth;
				pixels[i + 3] = 255;
			}
			i += 4;
		}
	}
	ctx.putImageData(imgData, 0, 0);
}
camera = new Camera([0, 0, 10], [0, 0, -1], [0, -1, 0], 60);
scene = Sphere([0, 0, -10], 10);
var start = new Date().getTime();
renderDepth(scene, camera);
var end = new Date().getTime();
console.log(end - start);
</script>